'use client';

import Image from 'next/image';
import Link from 'next/link';
import classNames from 'classnames';
import {
  type MouseEvent,
  useCallback,
  useEffect,
  useState,
  useTransition,
} from 'react';
import type { TMetadata } from '@/types';
import {
  logout,
  queryAllMessage,
  queryPostFollowMessage,
} from '@/services/api';
import { useMutation, useQuery } from '@tanstack/react-query';
import useUser from '@/hooks/useUser';
import type {
  IClientMessage,
  IConfigSite,
  IPagination,
  IPostFollowsMessage,
  IQueryParams,
  IUserOv,
} from '@/interfaces';
import useToast from '@/hooks/useToast';
import SearchModal from '@/app/[locale]/modal/search/search';
import useModal from '@/hooks/useModal';
import { nanoid } from 'nanoid';
import { useLocale, useTranslations } from 'use-intl';
import { useRouter } from 'next/navigation';
import { usePathname } from 'next-intl/client';

export const NavbarPage = ({
  metadata,
  stickyTop = true,
}: {
  metadata: TMetadata;
  stickyTop?: boolean;
}) => {
  return <Navbar metadata={metadata} stickyTop={stickyTop} />;
};

const Navbar = ({
  metadata,
  stickyTop = true,
}: {
  metadata: TMetadata;
  stickyTop?: boolean;
}) => {
  const userQuery = useUser(metadata);
  const t = useTranslations('Navbar');

  return (
    <nav
      className={classNames('navbar navbar-expand bg-body-tertiary', {
        'sticky-top': stickyTop,
      })}
    >
      <div className="container-fluid">
        <Logo metadata={metadata} />
        <div className="d-flex flex-grow-1 align-items-center gap-4 justify-content-between d-none d-md-flex">
          <ul className="navbar-nav">
            <LinkNavItem href="/" name={t('homePage')} />
            <LinkNavItem href="/sections" name={t('content')} />
            <MessageNavItem user={userQuery.data?.user} metadata={metadata} />
            <FollowMessageNavItem
              user={userQuery.data?.user}
              metadata={metadata}
            />
            <MoreNavItem
              user={userQuery.data?.user}
              siteConfig={userQuery.data?.siteConfig}
              metadata={metadata}
            />
            <AliasNavItem alias={userQuery.data?.user?.alias} />
          </ul>

          <div className="d-flex">
            <TranslateItem />
            <ColorModeItem />
          </div>
        </div>
      </div>
    </nav>
  );
};

const Logo = ({ metadata }: { metadata: TMetadata }) => {
  const env = metadata.env;

  return (
    <Link href="/" className="navbar-brand">
      <Image
        src="/images/logo.svg"
        alt={`${env.APP_NAME} - ${env.APP_URL_HOST}`}
        width={48}
        height={48}
        placeholder="blur"
        blurDataURL={env.APP_BLUR_DATA_URL}
        title={`${env.APP_NAME} - ${env.APP_URL_HOST}`}
      />
    </Link>
  );
};

export const TranslateItem = () => {
  const router = useRouter();
  const locale = useLocale();
  const [isPending, startTransition] = useTransition();
  const pathname = usePathname();
  const { show } = useToast();

  function onClickTranslate(value: string) {
    startTransition(() => {
      router.replace(`/${value}${pathname}`);
    });
  }

  return (
    <ul className="navbar-nav">
      <li className="nav-item dropstart">
        <a
          className="nav-link"
          role="button"
          data-bs-toggle="dropdown"
          aria-expanded="false"
        >
          <i className="bi bi-translate"></i>
        </a>
        <ul
          className="dropdown-menu text-center"
          style={{
            ['--bs-dropdown-min-width' as string]: '8rem',
          }}
        >
          <button
            disabled={isPending}
            onClick={onClickTranslate.bind(this, 'en')}
            type="button"
            className={classNames('dropdown-item d-flex align-items-center', {
              active: locale === 'en',
            })}
          >
            {isPending && (
              <span
                className="spinner-border spinner-border-sm me-2"
                role="status"
                aria-hidden="true"
              ></span>
            )}
            English
            {locale === 'en' && <i className="bi bi-check2 ms-2"></i>}
          </button>

          <button
            disabled={isPending}
            onClick={onClickTranslate.bind(this, 'zh')}
            type="button"
            className={classNames('dropdown-item d-flex align-items-center', {
              active: locale === 'zh',
            })}
          >
            {isPending && (
              <span
                className="spinner-border spinner-border-sm me-2"
                role="status"
                aria-hidden="true"
              ></span>
            )}
            简体中文
            {locale === 'zh' && <i className="bi bi-check2 ms-2"></i>}
          </button>
        </ul>
      </li>
    </ul>
  );
};

export const ColorModeItem = ({
  hidden,
  name,
  isShowDropdownToggle = false,
  aPy0 = false,
  callback,
}: {
  name?: string;
  hidden?: boolean;
  isShowDropdownToggle?: boolean;
  aPy0?: boolean;
  callback?: (theme: 'auto' | 'dark' | 'light') => void;
}) => {
  const [colorMode, setColorMode] = useState('auto');
  const t = useTranslations('Navbar');

  const getStoredTheme = useCallback(() => {
    return localStorage.getItem('theme');
  }, []);

  const setStoredTheme = useCallback((theme: string) => {
    localStorage.setItem('theme', theme);
  }, []);

  const getPreferredTheme = useCallback(() => {
    const storedTheme = getStoredTheme();
    if (storedTheme) {
      return storedTheme;
    }

    return matchMedia('(prefers-color-scheme: dark)').matches
      ? 'dark'
      : 'light';
  }, [getStoredTheme]);

  const setTheme = useCallback((theme: string) => {
    const qName = 'data-bs-theme';
    if (
      theme === 'auto' &&
      matchMedia('(prefers-color-scheme: dark)').matches
    ) {
      document.documentElement.setAttribute(qName, 'dark');
    } else {
      document.documentElement.setAttribute(qName, theme);
    }
    setColorMode(theme);
    if (typeof callback === 'function') {
      callback(theme as 'auto' | 'dark' | 'light');
    }
  }, []);

  const onClickColorMode = useCallback(
    (theme?: string) => {
      const preferredTheme = theme ? theme : getPreferredTheme();
      setStoredTheme(preferredTheme);
      setTheme(preferredTheme);
    },
    [getPreferredTheme, setStoredTheme, setTheme],
  );

  useEffect(() => {
    function handleChange() {
      const storedTheme = getStoredTheme();
      if (storedTheme !== 'light' && storedTheme !== 'dark') {
        setTheme(getPreferredTheme());
      }
    }

    if (typeof localStorage !== 'undefined') {
      onClickColorMode();
      matchMedia('(prefers-color-scheme: dark)').addEventListener(
        'change',
        handleChange,
      );
    }

    return () => {
      matchMedia('(prefers-color-scheme: dark)').removeEventListener(
        'change',
        handleChange,
      );
    };
  }, [getPreferredTheme, getStoredTheme, onClickColorMode, setTheme]);

  return (
    <>
      {!hidden && (
        <ul className="navbar-nav">
          <li className="nav-item dropstart">
            <a
              className={classNames('nav-link', {
                'dropdown-toggle': isShowDropdownToggle,
                'py-0': aPy0,
              })}
              role="button"
              data-bs-toggle="dropdown"
              aria-expanded="false"
            >
              {colorMode === 'light' &&
                (name ? name : <i className="bi bi-brightness-high-fill"></i>)}
              {colorMode === 'dark' &&
                (name ? name : <i className="bi bi-moon-stars-fill"></i>)}
              {colorMode === 'auto' &&
                (name ? name : <i className="bi bi-circle-half"></i>)}
            </a>
            <ul
              className="dropdown-menu text-center"
              style={{
                ['--bs-dropdown-min-width' as string]: '8rem',
              }}
            >
              <button
                onClick={onClickColorMode.bind(this, 'light')}
                type="button"
                className={classNames(
                  'dropdown-item d-flex align-items-center',
                  {
                    active: colorMode === 'light',
                  },
                )}
              >
                <i className="bi bi-brightness-high-fill me-2"></i>
                {t('light')}
                {colorMode === 'light' && <i className="bi bi-check2 ms-2"></i>}
              </button>

              <button
                onClick={onClickColorMode.bind(this, 'dark')}
                type="button"
                className={classNames(
                  'dropdown-item d-flex align-items-center',
                  {
                    active: colorMode === 'dark',
                  },
                )}
              >
                <i className="bi bi-moon-stars-fill me-2"></i>
                {t('dark')}
                {colorMode === 'dark' && <i className="bi bi-check2 ms-2"></i>}
              </button>

              <button
                onClick={onClickColorMode.bind(this, 'auto')}
                type="button"
                className={classNames(
                  'dropdown-item d-flex align-items-center',
                  {
                    active: colorMode === 'auto',
                  },
                )}
              >
                <i className="bi bi-circle-half me-2"></i>
                {t('auto')}
                {colorMode === 'auto' && <i className="bi bi-check2 ms-2"></i>}
              </button>
            </ul>
          </li>
        </ul>
      )}
    </>
  );
};

const LinkNavItem = ({ href, name }: { href: string; name: string }) => {
  return (
    <li className="nav-item">
      <Link href={href} className="nav-link">
        {name}
      </Link>
    </li>
  );
};

const FollowMessageNavItem = ({
  user,
  metadata,
}: {
  user: IUserOv | undefined;
  metadata: TMetadata;
}) => {
  const t = useTranslations('Navbar');
  const { showModal } = useModal({
    metadata,
  });

  const queryPostFollowMessageQuery = useQuery(
    ['/forum', '/posts', '/follows', '/message'],
    async () => {
      return (await queryPostFollowMessage()) as IPostFollowsMessage[];
    },
    {
      enabled: !!user,
    },
  );

  return (
    <>
      {user && (
        <li className="nav-item">
          <Link
            href="/follow"
            className="nav-link cursor-pointer d-flex align-items-center"
          >
            <span className="position-relative">
              {t('follow')}
              {queryPostFollowMessageQuery.data &&
                queryPostFollowMessageQuery.data.length > 0 && (
                  <span className="position-absolute top-0 start-100 translate-middle p-1 bg-danger border border-light rounded-circle">
                    <span className="visually-hidden">
                      {queryPostFollowMessageQuery.data.length}
                    </span>
                  </span>
                )}
            </span>
          </Link>
        </li>
      )}
    </>
  );
};

const MessageNavItem = ({
  user,
  metadata,
}: {
  user: IUserOv | undefined;
  metadata: TMetadata;
}) => {
  const t = useTranslations('Navbar');
  const [unreadCount, setUnreadCount] = useState(0);
  const { showModal } = useModal({
    metadata,
  });

  const queryAllMessageQuery = useQuery(
    ['/messages', {}],
    async (context) => {
      return (await queryAllMessage({
        query: context.queryKey[1] as IQueryParams,
      })) as IPagination<IClientMessage>;
    },
    {
      enabled: !!user,
    },
  );

  useEffect(() => {
    if (queryAllMessageQuery.data) {
      setUnreadCount(calculateUnreadCount(queryAllMessageQuery.data));
    }
  }, [queryAllMessageQuery.data]);

  function calculateUnreadCount(data: IPagination<IClientMessage>) {
    return (
      data.content.filter((item) => !item.messageRange && !item.state).length +
      data.content.filter((item) => item.state === 'UNREAD').length
    );
  }

  return (
    <>
      {user && (
        <li className="nav-item">
          <Link
            href="/message"
            className="nav-link cursor-pointer d-flex align-items-center"
          >
            <span className="position-relative">
              {t('message')}
              {unreadCount > 0 && (
                <span className="position-absolute top-0 start-100 translate-middle p-1 bg-danger border border-light rounded-circle">
                  <span className="visually-hidden">{unreadCount}</span>
                </span>
              )}
            </span>
          </Link>
        </li>
      )}
    </>
  );
};

const MoreNavItem = ({
  user,
  siteConfig,
  metadata,
}: {
  user: IUserOv | undefined;
  siteConfig: IConfigSite | undefined;
  metadata: TMetadata;
}) => {
  const t = useTranslations('Navbar');

  return (
    <li className="nav-item dropdown">
      <a
        className="nav-link dropdown-toggle"
        id="navbarDropdown"
        role="button"
        data-bs-toggle="dropdown"
        aria-expanded="false"
      >
        {t('more')}
      </a>
      <ul className="dropdown-menu" aria-labelledby="navbarDropdown">
        {user ? (
          <>
            <LinkDropdownItem href="/posts/new" name={t('createPost')} />
            <DropdownDivider />

            <LinkDropdownItem href={`/users/${user.id}`} name={t('profile')} />
            <LinkDropdownItem href="/admin" name={t('dashboard')} />
            <SearchDropdownItem metadata={metadata} />
            <DropdownDivider />

            <LogoutDropdownItem />
          </>
        ) : (
          <>
            <LinkDropdownItem href="/login" name={t('login')} />
            <LinkDropdownItem href="/register" name={t('register')} />
            <SearchDropdownItem metadata={metadata} />
          </>
        )}

        {siteConfig && (
          <>
            {Object.values(siteConfig).filter((item) => item).length > 1 && (
              <DropdownDivider />
            )}
            {siteConfig.helpLink && (
              <LinkDropdownItem href={siteConfig.helpLink} name={t('help')} />
            )}
            {siteConfig.feedbackLink && (
              <LinkDropdownItem
                href={siteConfig.feedbackLink}
                name={t('feedback')}
              />
            )}
            {siteConfig.reportLink && (
              <LinkDropdownItem
                href={siteConfig.reportLink}
                name={t('report')}
              />
            )}
          </>
        )}
      </ul>
    </li>
  );
};

const AliasNavItem = ({ alias }: { alias?: string | undefined }) => {
  return (
    <>
      {alias ? (
        <li className="nav-item cursor-not-allowed">
          <a className="nav-link disabled text-truncate">{alias}</a>
        </li>
      ) : (
        <></>
      )}
    </>
  );
};

const DropdownDivider = () => {
  return (
    <li>
      <hr className="dropdown-divider" />
    </li>
  );
};

const LinkDropdownItem = ({ href, name }: { href: string; name: string }) => {
  return (
    <li>
      <Link href={href} className="dropdown-item">
        {name}
      </Link>
    </li>
  );
};

const LogoutDropdownItem = () => {
  const t = useTranslations('Navbar');
  const { show } = useToast();

  const logoutMutation = useMutation(async () => {
    await logout();
  });

  async function onClickLogout(e: MouseEvent<HTMLAnchorElement>) {
    try {
      e.stopPropagation();
      e.preventDefault();

      await logoutMutation.mutateAsync();

      show({
        type: 'SUCCESS',
        message: t('logoutComplete'),
      });

      setTimeout(() => {
        show({
          type: 'INFO',
          message: t('reloadSoon'),
        });
      }, 1000);

      setTimeout(() => {
        if (
          location.href.includes('/admin') ||
          location.href.includes('/new') ||
          location.href.includes('/edit')
        ) {
          location.href = '/';
        } else {
          location.reload();
        }
      }, 1500);
    } catch (e) {
      logoutMutation.reset();
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  return (
    <li>
      <a onClick={onClickLogout} className="dropdown-item cursor-pointer">
        {t('logout')}
      </a>
    </li>
  );
};

const SearchDropdownItem = ({ metadata }: { metadata: TMetadata }) => {
  const t = useTranslations('Navbar');
  const { showModal } = useModal({ metadata });

  function onClickSearch(e: MouseEvent<HTMLAnchorElement>) {
    e.stopPropagation();
    e.preventDefault();

    const mid = nanoid();
    showModal({
      mid,
      centered: false,
      customContent: <SearchModal mid={mid} />,
    });
  }

  return (
    <li>
      <a onClick={onClickSearch} className="dropdown-item cursor-pointer">
        {t('search')}
      </a>
    </li>
  );
};
